In [1]:
import numpy as np
import scipy as sp
import pandas as pd

Scalar, Vector and Matrices

Scalar


In [2]:
sca = 24
sca


Out[2]:
24

Vector


In [3]:
vec = np.array([1, 12, 34])
vec


Out[3]:
array([ 1, 12, 34])

Matrices

Ones matrices


In [4]:
np.ones((3,3))


Out[4]:
array([[1., 1., 1.],
       [1., 1., 1.],
       [1., 1., 1.]])

Zeros matrices


In [5]:
np.zeros((4,2))


Out[5]:
array([[0., 0.],
       [0., 0.],
       [0., 0.],
       [0., 0.]])

Diagonal matrices


In [6]:
np.diag([1, 23])


Out[6]:
array([[ 1,  0],
       [ 0, 23]])

Identity matrices


In [7]:
np.eye(2)


Out[7]:
array([[1., 0.],
       [0., 1.]])

Symmetric matrices


In [8]:
sym = np.matrix('2,3,1;3,4,-1;1,-1,1')
sym


Out[8]:
matrix([[ 2,  3,  1],
        [ 3,  4, -1],
        [ 1, -1,  1]])

In [9]:
sym.T


Out[9]:
matrix([[ 2,  3,  1],
        [ 3,  4, -1],
        [ 1, -1,  1]])

Skew-symmetric matrices


In [10]:
ssym = np.matrix('2,3,1;-3,4,1;-1,-1,1')
ssym


Out[10]:
matrix([[ 2,  3,  1],
        [-3,  4,  1],
        [-1, -1,  1]])

In [11]:
ssym.T


Out[11]:
matrix([[ 2, -3, -1],
        [ 3,  4, -1],
        [ 1,  1,  1]])

Upper Traingular Matrix


In [12]:
mat = np.array([[10,5,9],
                [2,20,6],
                [8,3,30]]).reshape(3,3)
mat


Out[12]:
array([[10,  5,  9],
       [ 2, 20,  6],
       [ 8,  3, 30]])

In [13]:
np.triu(mat,1)


Out[13]:
array([[0, 5, 9],
       [0, 0, 6],
       [0, 0, 0]])

Lower Triangular Matrix


In [14]:
np.tril(mat, -1)


Out[14]:
array([[0, 0, 0],
       [2, 0, 0],
       [8, 3, 0]])

Operations over vectors and matrices

Vector Addition


In [15]:
vec1 = pd.Series([1, 2, 3, 4])
vec2 = pd.Series([2, 3, 40, 55])
vec1 + vec2


Out[15]:
0     3
1     5
2    43
3    59
dtype: int64

Matrix Addition


In [16]:
mat1 = pd.DataFrame([[1, 23, 5], [55, 21, 96]])
mat2 = pd.DataFrame([[11, 43, 45], [115, 81, 23]])
mat1 + mat2


Out[16]:
0 1 2
0 12 66 50
1 170 102 119

Scalar-Vector Multiplication


In [17]:
sca = 5
vec = pd.Series([1, 2, 5, 10])
sca * vec


Out[17]:
0     5
1    10
2    25
3    50
dtype: int64

Inner Product Matrix Multiplication


In [18]:
mat1 = pd.DataFrame([[1, 23, 5], [55, 21, 96]])
mat2 = pd.DataFrame([[11, 43], [115, 81], [5, 1]])
mat1.dot(mat2)


Out[18]:
0 1
0 2681 1911
1 3500 4162

Angles between vectors

$Cos\theta=\frac{v^T_1.v_2}{||v_1||.||v_2||}$


In [19]:
v1 = pd.Series([3, -1, 2])
v2 = pd.Series([2, 4, -1])

angle = np.arccos((v1.dot(v2))/np.linalg.norm(v1)*np.linalg.norm(v2))

# Angle in degrees
angle * 180/np.pi


Out[19]:
90.0

Matrix-Vector Multiplication


In [20]:
mat = pd.DataFrame(np.arange(1,10).reshape(3,-1).T)
vec = pd.Series([1, -1, 2])
print(mat)
vec


   0  1  2
0  1  4  7
1  2  5  8
2  3  6  9
Out[20]:
0    1
1   -1
2    2
dtype: int64

In [21]:
vec * mat


Out[21]:
0 1 2
0 1 -4 14
1 2 -5 16
2 3 -6 18

In [22]:
vec.dot(mat)


Out[22]:
0     5
1    11
2    17
dtype: int64

In [23]:
mat.dot(vec)


Out[23]:
0    11
1    13
2    15
dtype: int64

Adjacency Matrix


In [24]:
mat = pd.DataFrame([[0, 1, 0, 0, 1], 
                     [0, 0, 1, 1, 0], 
                     [0, 0, 0, 1, 0], 
                     [0, 1, 0, 0, 0],
                     [0, 0, 0, 1, 0]])
mat.dot(mat)


Out[24]:
0 1 2 3 4
0 0 0 1 2 0
1 0 1 0 1 0
2 0 1 0 0 0
3 0 0 1 1 0
4 0 1 0 0 0

Permutation Matrix


In [25]:
I1 = np.matrix('1, 0, 0; 0, 0, 1;0, 1, 0')
mat = pd.DataFrame(np.arange(1,10).reshape(3,-1).T)
print(I1)
print(mat)


[[1 0 0]
 [0 0 1]
 [0 1 0]]
   0  1  2
0  1  4  7
1  2  5  8
2  3  6  9

In [26]:
# Pre-multiplying
I1.dot(mat)      # resulted into exchanging of row 2 and 3


Out[26]:
matrix([[1, 4, 7],
        [3, 6, 9],
        [2, 5, 8]])

In [27]:
# Post-multiplying
mat.dot(I1)      # resulted into exchanging of column 2 and 3


Out[27]:
0 1 2
0 1 7 4
1 2 8 5
2 3 9 6

Orthogonal Projection

$p = v_2.\frac{v^T_2.v_1}{v^T_2.v_2}$


In [28]:
v1 = np.array([2, 3])
v2 = np.array([4, 4])

v2.dot((v2.T.dot(v1)/v2.T.dot(v2)))


Out[28]:
array([2.5, 2.5])

Determinants


In [29]:
np.linalg.det([[1, 2], 
               [3, 4]])


Out[29]:
-2.0000000000000004

Matrix Inversion


In [30]:
np.linalg.inv([[1, 2], 
               [3, 4]])


Out[30]:
array([[-2. ,  1. ],
       [ 1.5, -0.5]])

Orthogonal Matrix

$Q*Q^T = I$


In [31]:
ortho = np.matrix([[1/np.sqrt(2), 1/np.sqrt(2), 0], 
                   [0, 0, 1],
                   [1/np.sqrt(2), -1/np.sqrt(2), 0]])
ortho


Out[31]:
matrix([[ 0.70710678,  0.70710678,  0.        ],
        [ 0.        ,  0.        ,  1.        ],
        [ 0.70710678, -0.70710678,  0.        ]])

In [32]:
ortho*ortho.T


Out[32]:
matrix([[ 1.00000000e+00,  0.00000000e+00, -2.23711432e-17],
        [ 0.00000000e+00,  1.00000000e+00,  0.00000000e+00],
        [-2.23711432e-17,  0.00000000e+00,  1.00000000e+00]])

Rank of a matrix


In [33]:
np.linalg.matrix_rank([[1, 2], [3, 4]])


Out[33]:
2

Transformation

Stretching


In [34]:
# Stretching a vector by scale 2
2 * np.array([2, 23])


Out[34]:
array([ 4, 46])

In [35]:
# Stretching a matrix by scale 2.5
2.5 * np.matrix([[1, 2], [3, 4]])


Out[35]:
matrix([[ 2.5,  5. ],
        [ 7.5, 10. ]])

Reflection


In [36]:
coord = np.matrix([[-1, -2, -3], 
                   [1, 2, 1]])
coord


Out[36]:
matrix([[-1, -2, -3],
        [ 1,  2,  1]])

Across x-axis


In [37]:
np.matrix([[1, 0],
          [0, -1]]) * coord


Out[37]:
matrix([[-1, -2, -3],
        [-1, -2, -1]])

Across y-axis


In [38]:
np.matrix([[-1, 0],
          [0, 1]]) * coord


Out[38]:
matrix([[1, 2, 3],
        [1, 2, 1]])

Across origin


In [39]:
np.matrix([[-1, 0],
          [0, -1]]) * coord


Out[39]:
matrix([[ 1,  2,  3],
        [-1, -2, -1]])

Across x = y


In [40]:
np.matrix([[0, 1],
          [1, 0]]) * coord


Out[40]:
matrix([[ 1,  2,  1],
        [-1, -2, -3]])

Rotation

Rotation of an object by $\theta$ degrees is characterised by matrix $A = \begin{bmatrix} Cos\theta & Sin\theta\\ -Sin\theta & Cos\theta \end{bmatrix}$ where $\theta$ represents the angle in counter clockwise direction.


In [41]:
np.matrix([[0, 1],
          [-1, 0]]) * coord


Out[41]:
matrix([[1, 2, 1],
        [1, 2, 3]])

Projection

On x-axis


In [42]:
np.matrix([[1, 0],
          [0, 0]]) * coord


Out[42]:
matrix([[-1, -2, -3],
        [ 0,  0,  0]])

On y-axis


In [43]:
np.matrix([[0, 0],
          [0, 1]]) * coord


Out[43]:
matrix([[0, 0, 0],
        [1, 2, 1]])

Solving system of Linear Eq on square matrix

$Ax=B$


In [44]:
mat = np.array([1, 3, -1, 4, 2, 5, 4, 19, 2, 3, -1, 7]).reshape(3,-1)
mat
A = mat[:,:3]
B = mat[:,3]

In [45]:
np.linalg.solve(A,B)


Out[45]:
array([3., 1., 2.])

Solving system of Linear Eq on non-square matrix

$Ax=B$


In [46]:
mat = np.array([1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3, 1, 1, 1, 6]).reshape(4,-1)
mat
A = mat[:,:3]
B = mat[:,3]

In [47]:
np.linalg.lstsq(A,B)[0]


C:\Anaconda\lib\site-packages\ipykernel_launcher.py:1: FutureWarning: `rcond` parameter will change to the default of machine precision times ``max(M, N)`` where M and N are the input matrix dimensions.
To use the future default and silence this warning we advise to pass `rcond=None`, to keep using the old, explicitly pass `rcond=-1`.
  """Entry point for launching an IPython kernel.
Out[47]:
array([1., 2., 3.])

Eigenvalues and Eigenvectors


In [48]:
mat = np.matrix([[2, np.sqrt(2)], [np.sqrt(2), 1]])
mat


Out[48]:
matrix([[2.        , 1.41421356],
        [1.41421356, 1.        ]])

Eigen values


In [49]:
np.linalg.eig(mat)[0]


Out[49]:
array([ 3.00000000e+00, -2.22044605e-16])

Eigen vectors


In [50]:
np.linalg.eig(mat)[1]


Out[50]:
matrix([[ 0.81649658, -0.57735027],
        [ 0.57735027,  0.81649658]])

Diagonal Form

$Inv(EigVec).mat.EigVec$


In [51]:
mat = np.arange(1,10).reshape(3,-1).T
mat


Out[51]:
array([[1, 4, 7],
       [2, 5, 8],
       [3, 6, 9]])

In [52]:
# Eigen values
np.round(np.linalg.eig(mat)[0]) + 0 # Addiing 0 to remove extra minus sign


Out[52]:
array([16., -1.,  0.])

In [53]:
# Diagonal values are Eigenvalues
np.round(np.linalg.inv(np.linalg.eig(mat)[1]).dot(mat).dot(np.linalg.eig(mat)[1])) + 0


Out[53]:
array([[16.,  0.,  0.],
       [ 0., -1.,  0.],
       [ 0.,  0.,  0.]])

Positive Definite Matrix


In [54]:
mat = np.matrix([11, 20, 13, 1, 15, 6, 7, 8, 90]).reshape(3,-1)
np.linalg.eig(mat)[0] # All eigenvalues are greater than 0, hence "mat" is a Positive Definite matrix


Out[54]:
array([91.90672643,  8.37848189, 15.71479168])

QR decomposition


In [55]:
np.linalg.qr(mat)


Out[55]:
(matrix([[-0.84119102, -0.09199896, -0.53285444],
         [-0.07647191, -0.95527686,  0.28565393],
         [-0.53530338,  0.28103792,  0.79653499]]),
 matrix([[-13.07669683, -22.25332619, -59.5716189 ],
         [  0.        , -13.92082877,  18.36576477],
         [  0.        ,   0.        ,  66.47496451]]))

Cholesly decomposition


In [56]:
np.linalg.cholesky(mat)


Out[56]:
matrix([[3.31662479, 0.        , 0.        ],
        [0.30151134, 3.8612292 , 0.        ],
        [2.11057941, 1.90707052, 9.05033351]])

Spectral Value decomposition


In [57]:
np.linalg.svd(mat)


Out[57]:
(matrix([[ 0.18014094, -0.81759681,  0.54688636],
         [ 0.08750015, -0.54045817, -0.83680864],
         [ 0.97974127,  0.19859614, -0.0258188 ]]),
 array([92.36486684, 24.60443394,  5.32477271]),
 matrix([[ 0.0966519 ,  0.1380747 ,  0.98569457],
         [-0.33099116, -0.92950887,  0.1626595 ],
         [ 0.93867101, -0.34197754, -0.04413729]]))